import { ref, computed } from "vue";
import { rAF, cancleRAF } from '../util/rAF'

type CurrentTime = {
    days: number
    hours: number
    minutes: number
    seconds: number
    milliseconds: number
    total: number
}

const SECOND = 1000
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR

const parseTime = (time: number) => {
    const days = Math.floor(time / DAY)
    const hours = Math.floor((time % DAY) / HOUR)
    const minutes = Math.floor((time % HOUR) / MINUTE)
    const seconds = Math.floor((time % MINUTE) / SECOND)
    const milliseconds = Math.floor(time % SECOND)

    return {
        days,
        hours,
        minutes,
        seconds,
        milliseconds,
        total: time
    }
}


type UseCountDownOptions = {
    time: number
    millesecond?: boolean // 是否需要毫秒级
    onChange?: (current: CurrentTime) => void
    onFinish?: () => void
}

// 非毫秒场景计算两个时间是否属于同一秒
const isSameSecond  = (time1: number, time2: number) => {
    return Math.floor(time1 / SECOND) ===  Math.floor(time2 / SECOND)
}

export function useCountDown(options: UseCountDownOptions) {
    let rafId: number // RAF回调函数返回值
    let endTime: number
    let counting: boolean // 是否正在计时
    const remain = ref(options.time) // 剩余时间
    const current = computed(() => parseTime(remain.value)) // computed中监听并计算当前时间

    const pause = () => {
        counting = false
        cancleRAF(rafId)
    }
    const getCurrentRemain = () => Math.max(endTime - Date.now(), 0)

    const setRemain = (value: number) => {
        remain.value = value
        options.onChange?.(current.value)

        if (value === 0) {
            pause()
            options.onFinish?.()
        }
    }

    const miroTick = () => {
        rafId = rAF(() => {
            if (counting) {
                // 倒计时中计算当前剩余时间
                const currrntRemain = getCurrentRemain()
                setRemain(currrntRemain)

                if (remain.value > 0) {
                    miroTick()
                }
            }
        })
    }

    const macroTick = () => {
        rafId = rAF(() => {
            if (counting) {
                // 倒计时中计算当前剩余时间
                const currrntRemain = getCurrentRemain()
                if (!isSameSecond(currrntRemain, remain.value) || currrntRemain === 0) {
                    setRemain(currrntRemain)
                }

                if (remain.value > 0) {
                    macroTick()
                }
            }
        })
    }

    const tick = () => {
        if (options.millesecond) {
            miroTick() // 毫秒级别倒计时
        } else {
            macroTick() // 非毫秒级别倒计时
        }
    }

    const start = () => {
        if (!counting) {
            endTime = Date.now() + remain.value
            counting = true
            tick()
        }
    }

    const reset = (totalTime = options.time) => {
        pause()
        remain.value = totalTime
    }

    return {
        start,
        pause,
        reset,
        current
    }
}